package at.ac.tuwien.dse.health.messenger.dict;

import at.ac.tuwien.dse.health.entity.Doctor;
import at.ac.tuwien.dse.health.entity.Hospital;
import at.ac.tuwien.dse.health.entity.Patient;
import at.ac.tuwien.dse.health.entity.SurgerySlot;
import at.ac.tuwien.dse.health.messenger.annotation.Dynamic;
import at.ac.tuwien.dse.health.reservation.ReservationCancellation;
import at.ac.tuwien.dse.health.reservation.ReservationConfirmation;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * Produces messages for objects related to surgery slot reservations.
 *
 * @author Bernhard Nickel
 * @author Gregor Schauer
 * @author Dominik Strasser
 */
@Dynamic
public class ReservationDictionary {
	static final ThreadLocal<SimpleDateFormat> DATE_FORMAT = new ThreadLocal<SimpleDateFormat>() {
		@Override
		protected SimpleDateFormat initialValue() {
			return new SimpleDateFormat("dd.MM.yyyy HH:mm");
		}
	};

	/**
	 * Creates a title message for {@link ReservationConfirmation ReservationConfirmations}.
	 *
	 * @param confirmation the confirmation for the reservation
	 * @return the title
	 */
	@Dynamic
	public String titleReservationConfirmation(ReservationConfirmation confirmation) {
		return "Reservierungsbestätigung";
	}

	/**
	 * Creates a title message for {@link ReservationCancellation ReservationCancellations}.
	 *
	 * @param cancellation the cancellation of the reservation
	 * @return the title
	 */
	@Dynamic
	public String titleReservationCancellation(ReservationCancellation cancellation) {
		return "Reservierungsstornierung";
	}

	/**
	 * Creates a message for a {@link Patient} stating that a given {@link SurgerySlot} was reserved successfully by a
	 * certain doctor.
	 *
	 * @param confirmation the confirmation for the reservation
	 * @param doctor       the doctor requested the slot
	 * @param slot         the slot reserved
	 * @return the message
	 */
	@Dynamic
	public String patientReservationConfirmation(ReservationConfirmation confirmation, Doctor doctor, SurgerySlot slot) {
		return String.format("Ein Operationstermin am %s bei %s im %s wurde für Sie reserviert.",
				date(slot.getStartDate()), doctor, slot.getHospital());
	}

	/**
	 * Creates a message for a {@link Doctor} stating that a given {@link SurgerySlot} was reserved successfully.
	 *
	 * @param confirmation the confirmation for the reservation
	 * @param patient      the patient the slot was requested for
	 * @param slot         the slot reserved
	 * @return the message
	 */
	@Dynamic
	public String doctorReservationConfirmation(ReservationConfirmation confirmation, Patient patient, SurgerySlot slot) {
		return String.format("Ein Operationstermin am %s für %s im %s wurde für Sie reserviert.",
				date(slot.getStartDate()), patient, slot.getHospital());
	}

	/**
	 * Creates a message for a {@link Hospital} stating that a given {@link SurgerySlot} was reserved successfully.
	 *
	 * @param confirmation the confirmation for the reservation
	 * @param doctor       the doctor who reserved the slot
	 * @param patient      the patient the slot was requested for
	 * @param slot         the slot reserved
	 * @return the message
	 */
	@Dynamic
	public String hospitalReservationConfirmation(ReservationConfirmation confirmation, Doctor doctor, Patient patient, SurgerySlot slot) {
		return String.format("Ein Operationstermin am %s für %s wurde von %s reserviert.",
				date(slot.getStartDate()), patient, doctor);
	}

	/**
	 * Creates a message for a {@link Patient} stating that there is no {@link SurgerySlot} available for a certain
	 * reservation request.
	 *
	 * @param confirmation the confirmation for the reservation
	 * @param doctor       the doctor requested the slot
	 * @return the message
	 */
	@Dynamic
	public String patientReservationFailed(ReservationConfirmation confirmation, Doctor doctor) {
		return String.format("Es konnte kein Operationstermin für Sie reserviert werden, da im Umkreis von %d km kein OP der Abteilung %s frei ist",
				confirmation.getRequest().getRadius(), confirmation.getRequest().getType());
	}

	/**
	 * Creates a message for a {@link Doctor} stating that there is no {@link SurgerySlot} available for a certain
	 * reservation request.
	 *
	 * @param confirmation the confirmation for the reservation
	 * @param patient      the patient the slot should have been requested for
	 * @return the message
	 */
	@Dynamic
	public String doctorReservationFailed(ReservationConfirmation confirmation, Patient patient) {
		return String.format("Es konnte kein Operationstermin für %s reserviert werden, da im Umkreis von %d km kein OP der Abteilung %s frei ist",
				patient, confirmation.getRequest().getRadius(), confirmation.getRequest().getType());
	}

	/**
	 * Creates a message for a {@link Patient} stating that a given {@link SurgerySlot} was cancelled.
	 *
	 * @param cancellation the cancellation of the reservation
	 * @param doctor       the doctor requested the slot
	 * @param slot         the slot reserved
	 * @return the message
	 */
	@Dynamic
	public String patientReservationCancellation(ReservationCancellation cancellation, Doctor doctor, SurgerySlot slot) {
		return String.format("Der Operationstermin am %s bei %s im %s wurde storniert.",
				date(cancellation.getStartDate()), doctor, slot.getHospital());
	}

	/**
	 * Creates a message for a {@link Doctor} stating that a given {@link SurgerySlot} was cancelled.
	 *
	 * @param cancellation the cancellation of the reservation
	 * @param patient      the patient the slot was requested for
	 * @param slot         the slot reserved
	 * @return the message
	 */
	@Dynamic
	public String doctorReservationCancelled(ReservationCancellation cancellation, Patient patient, SurgerySlot slot) {
		return String.format("Der Operationstermin am %s für %s im %s wurde storniert.",
				date(cancellation.getStartDate()), patient, slot.getHospital());
	}

	/**
	 * Creates a message for a {@link Hospital} stating that a given {@link SurgerySlot} was cancelled.
	 *
	 * @param cancellation the cancellation of the reservation
	 * @param doctor       the doctor who reserved the slot
	 * @param patient      the patient the slot was requested for
	 * @return the message
	 */
	@Dynamic
	public String hospitalReservationCanceled(ReservationCancellation cancellation, Doctor doctor, Patient patient) {
		return String.format("Der Operationstermin am %s für %s reserviert von %s wurde storniert.",
				date(cancellation.getStartDate()), patient, doctor);
	}

	/**
	 * Formats the given {@link Date} using the the {@link #DATE_FORMAT}.
	 *
	 * @param date the date to format
	 * @return the message
	 * @see #date(java.util.Date, java.text.DateFormat)
	 */
	@Dynamic
	public String date(Date date) {
		return date(date, DATE_FORMAT.get());
	}

	/**
	 * Formats the given {@link Date} using the provided {@link DateFormat}.
	 *
	 * @param date       the date to format
	 * @param dateFormat the format to use
	 * @return the message
	 */
	@Dynamic
	public String date(Date date, DateFormat dateFormat) {
		return dateFormat.format(date);
	}
}
